/**
*		@file Parent.cpp
*		@brief Parent class
*
*		@author Kong Ling Ming
*
*		@date 1/25/2012
*/

#include "Parent.h"

vector<ParentEntry*>	Parent::vp_parent_entries_;
vector<StmtSet>			Parent::parent_table_;
vector<StmtSet>			Parent::parent_table_t_;
vector<StmtSet>			Parent::parent_adv_table_;
vector<StmtSet>			Parent::parent_adv_table_t_;

StmtSet					Parent::parent_has_s0_;
StmtSet					Parent::parent_has_0s_;
bool					Parent::parent_has_00_;

void Parent::SetParent(StmtNum stmt_num_left, StmtNum stmt_num_right)
{
	ParentEntry* p_parent_entry_temp = new ParentEntry;
	p_parent_entry_temp->stmt_num_left = stmt_num_left;
	p_parent_entry_temp->stmt_num_right = stmt_num_right;

	vp_parent_entries_.push_back(p_parent_entry_temp);
	return;
}

void Parent::RebuildParent()
{
	parent_table_.resize(StmtTable::GetSize());
	for(int i = 0; i < StmtTable::GetSize(); i++)
	{
		parent_table_[i].resize(StmtTable::GetSize());
	}
	
	// copy data from vector of parent entries to parent table
	for(unsigned int i = 0; i < vp_parent_entries_.size(); i++)
	{
		parent_table_[vp_parent_entries_[i]->stmt_num_left-1][vp_parent_entries_[i]->stmt_num_right-1] = true;
	}
	
	vp_parent_entries_.clear();

	// build for parent*
	for(int stmt_num_left = 1; stmt_num_left <= StmtTable::GetSize(); stmt_num_left++ )
	{
		// allocate return result
		StmtSet stmt_set_result (StmtTable::GetSize(), false);

		// create a queue and push the first element
		queue<StmtSet> queue_stmt_set;
		queue_stmt_set.push( GetParentRight(stmt_num_left) );

		// construct return result
		while( !queue_stmt_set.empty() )
		{
			// get the front element
			StmtSet stmt_set_temp = queue_stmt_set.front();
			queue_stmt_set.pop();

			// push more element into the queue if needed
			for( int i = 0; i < StmtTable::GetSize(); i++ )
			{
				if( stmt_set_temp[i] )
					queue_stmt_set.push( GetParentRight(i+1) );
			}

			// accumulate result
			stmt_set_result = LogicOR<StmtSet>( stmt_set_result, stmt_set_temp );
		}

		parent_adv_table_.push_back(stmt_set_result);
	}
	
	parent_table_t_ = parent_table_;
	parent_adv_table_t_ = parent_adv_table_;
	for( int i = 0; i < StmtTable::GetSize(); i++ )
	{
		for( int j = 0; j < StmtTable::GetSize(); j++ )
		{
			parent_table_t_[i][j] = parent_table_[j][i];
			parent_adv_table_t_[i][j] = parent_adv_table_[j][i];
		}
	}
	parent_has_s0_.resize(StmtTable::GetSize());
	parent_has_0s_.resize(StmtTable::GetSize());
	parent_has_00_ = false;
	return;
}

void Parent::CompleteParent()
{
	for( int i = 0; i < StmtTable::GetSize(); i++ )	parent_has_s0_[i] = IsAny<StmtSet>(parent_table_[i]);
	for( int i = 0; i < StmtTable::GetSize(); i++ )	parent_has_0s_[i] = IsAny<StmtSet>(parent_table_t_[i]);
	parent_has_00_ = IsAny<StmtSet>(parent_has_s0_);
	return;
}

StmtSet& Parent::GetParentRight(StmtNum stmt_num_left)
{
	return parent_table_[stmt_num_left - 1];
}

StmtSet& Parent::GetParentLeft(StmtNum stmt_num_right)
{
	return parent_table_t_[stmt_num_right - 1];
}

StmtSet& Parent::GetParentAdvRight(StmtNum stmt_num_left)
{
	return parent_adv_table_[stmt_num_left - 1];
}

StmtSet& Parent::GetParentAdvLeft(StmtNum stmt_num_right)
{
	return parent_adv_table_t_[stmt_num_right - 1];
}

bool Parent::IsParent(StmtNum stmt_num_left, StmtNum stmt_num_right)
{
	if( stmt_num_left > StmtTable::GetSize() || stmt_num_right > StmtTable::GetSize() )
		return false;
	if( stmt_num_left == 0 )
	{
		if( stmt_num_right == 0 )
			return parent_has_00_;
		else
			return parent_has_0s_[stmt_num_right - 1];
	}
	else
	{
		if( stmt_num_right == 0 )
			return parent_has_s0_[stmt_num_left - 1];
		else
			return parent_table_[stmt_num_left - 1][stmt_num_right - 1];
	}
}
	
// step1: create a queue and push the first element
// step2: find match
bool Parent::IsParentAdv(StmtNum stmt_num_left, StmtNum stmt_num_right)
{
	if( stmt_num_left > StmtTable::GetSize() || stmt_num_right > StmtTable::GetSize() )
		return false;
	if( stmt_num_left == 0 )
	{
		if( stmt_num_right == 0 )
			return parent_has_00_;
		else
			return parent_has_0s_[stmt_num_right - 1];
	}
	else
	{
		if( stmt_num_right == 0 )
			return parent_has_s0_[stmt_num_left - 1];
		else
			return parent_adv_table_[stmt_num_left - 1][stmt_num_right - 1];
	}
}

string Parent::ToString()
{
	stringstream ss_result;
	ss_result << "Parent :\n";
	for( int i = 0; i < StmtTable::GetSize(); i++ )
	{
		ss_result << (i+1)  << " : ";
		for( int j = 0; j < StmtTable::GetSize(); j++ )
			if( parent_table_[i][j] )
				ss_result << (j+1) <<" ";
		ss_result << "\n";
	}
	ss_result << "Parent* :\n";
	for( int i = 0; i < StmtTable::GetSize(); i++ )
	{
		ss_result << (i+1)  << " : ";
		for( int j = 0; j < StmtTable::GetSize(); j++ )
			if( parent_adv_table_[i][j] )
				ss_result << (j+1) <<" ";
		ss_result << "\n";
	}
	return ss_result.str();
}